﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace wsserver
{
    // Структура статистических данных героя
	public struct HeroStats
	{
		int health;
		int protection;
		int attack;
		int magic_power;
		int mana;
	}
	
	// Структура ресурсов города
	public struct Resources
	{
		public int gold;		// количество золота
		public int silver;		// серебро
		public int cuprum;		// медь
		public int stannum;	// олово
		public int bronze;		// бронза = медь + олово
		public int wood;		// лес
		public int food;		// еда
		// etc.
		public Resources(int gold, int silver, int cuprum, int stannum, int bronze, int wood, int food)
		{
			this.gold = gold;
			this.silver = silver;
			this.cuprum = cuprum;
			this.stannum = stannum;
			this.bronze = bronze;
			this.wood = wood;
			this.food = food;
		}
	}
	
	// коэффициент добычи ресурса
	public struct RateOfResExtraction
	{
		public int gold;		// количество золота
		public int silver;		// серебро
		public int cuprum;		// медь
		public int stannum;		// олово
		public int wood;		// лес
		public int food;		// еда
		// etc.
		public RateOfResExtraction(int gold, int silver, int cuprum, int stannum, int wood, int food)
		{
			this.gold = gold;
			this.silver = silver;
			this.cuprum = cuprum;
			this.stannum = stannum;
			this.wood = wood;
			this.food = food;
		}
	}
	
	class Town
	{
		public string name;		// название города
		
		/* Местоположение на карте */
		public int xcoords;
		public int ycoords;
		
		public List<Resource> Users_resources
		{
			get
			{
				return _users_resources;
			}
		}
		public List<Resource> _users_resources;
		
		public Resources resources;
		public RateOfResExtraction rate_of_res;
		public Town(string val_name, int val_x, int val_y)
		{
			xcoords = val_x;
			ycoords = val_y;
			name = val_name;
			
			// инициализируем коэффициент добычи ресурсов
			rate_of_res.gold = 5;
			rate_of_res.silver = 4;
			rate_of_res.cuprum = 3;
			rate_of_res.stannum = 2;
			rate_of_res.wood = 10;
			rate_of_res.food = 10;
			
			// инициализация ресурсов города
			resources.gold = 0;
			resources.silver = 0;
			resources.cuprum = 0;
			resources.stannum = 0;
			resources.bronze = 0;
			resources.wood = 0;
			resources.food = 0;
			
			_users_resources = new List<Resource>();
		}
	}
	
	class User
    {
        //сообщение отправляется сразу после соединения
        public static string WelcomeMessage = "Введите ник";
        
		public int xcoords;
		public int ycoords;
		
		public bool hero_in_town = true;
		
		public HeroStats hero_stats;
		public Town town;
		
		public string team = "NONE";
		public bool user_is_ready = false;
		public bool artifact_raised = false;
		
		//true если ник установлен
        public bool Authentificated
        {
            get;
            set;
        }

        public bool Alive
        {
            get;
            set;
        }

        //имя клиента
        public string Nick
        {
            get;
            set;
        }

        private Thread recieveThread;
        private TcpClient client;
        private NetworkStream stream;

        public delegate void RecieveEventHandler(User sender, string message);
        public delegate void DisconnectedEventHandler(User sender);

        //происходит по приему сообщений
        public event RecieveEventHandler RecieveMessage;

        //происходит по отсоединению клиента
        public event DisconnectedEventHandler Disconnect;

        //констуктор клиента
        public User(TcpClient tcpClient, RecieveEventHandler recieveHandler, DisconnectedEventHandler disconnectHandler)
        {
            
            Authentificated = false;
            Nick = "";
            client = tcpClient;
            stream = client.GetStream();
            RecieveMessage += recieveHandler;
            Disconnect += disconnectHandler;
            Alive = true;
            
            //создание нового потока для приема сообщений
            recieveThread = new Thread(startRead);
            recieveThread.Start();

            SendMessage(WelcomeMessage);
        }


        public void Stop()
        {
            Alive = false;
            if (recieveThread != null)
                recieveThread.Abort();
            client.Close();
        }

        private void startRead()
        {
            try
            {
                while (true)
                {
                    byte[] data = new byte[1000];
                    StringBuilder s = new StringBuilder();
                    int read = 0;
                    while (!stream.DataAvailable)
                        Thread.Sleep(50);
                    while ((read = stream.Read(data, 0, 1000)) != 0)
                    {
                        //первая часть сообщения
                        int start = 0;
                        for (; start < read; start++)
                            if (data[start] == 0x00)
                                break;
                        if (start == read)
                            start = -1;

                        //вторая часть сообщения
                        int finish = read - 1;
                        for (; finish >= 0; finish--)
                            if (data[finish] == 0xff)
                                break;
                        if (finish == -1)
                            finish = 1000;

                        s.Append(Encoding.UTF8.GetString(data, start + 1, finish - 1 - start));				
						
                        //if finish == 1000 - сообщение больше, чем буфер
                            break;
                    }
                    if (s.Length > 0)
					{
						JObject jo = JObject.Parse(s.ToString());
						if((string)jo["type"] == "ChatMessage")
                        	RecieveMessage(this, s.ToString());
						if((string)jo["type"] == "Action")
							RecieveMessage(this, s.ToString());
						if((string)jo["type"] == "Stroke")
							SendData(s.ToString());
					}
					
					StringBuilder sb = new StringBuilder("");									
                }
            }
            catch
            {
                if (client.Connected)
                    client.Close();
                Alive = false;
                Disconnect(this);
            }
        }			
		

        //отправление сообщения клиенту
        public void SendMessage(string message)
        {
            try
            {
                if (message != "")
                {
                    //Opening byte
                    byte[] begin = new byte[1] { 0x00 };
                    //Closing byte
                    byte[] end = new byte[1] { 0xFF };
                    //Message body
                    byte[] msg = Encoding.UTF8.GetBytes(message);

                    stream.Write(begin, 0, 1);
                    stream.Write(msg, 0, msg.Length);
                    stream.Write(end, 0, 1);
                }
            }
            catch
            {
                if (client.Connected)
                    client.Close();
                Alive = false;
                Disconnect(this);
            }
        }
		
		public void SendData(string message)
		{
			try
			{
				//Opening byte
                byte[] begin = new byte[1] { 0x00 };
                //Closing byte
                byte[] end = new byte[1] { 0xFF };
                //Message body
                byte[] msg = Encoding.UTF8.GetBytes(message);

                stream.Write(begin, 0, 1);
                stream.Write(msg, 0, msg.Length);
                stream.Write(end, 0, 1);
			}
			catch
			{
			}
		}
    }
}
